//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <elasysapi.h>
#include <sdl.h>
#include "keyboard.h"
#include "keyboard_internal.h"
#include "notifiercenter.h"

static CKeyboard * g_pKeyboard = NULL;

static void _Keyboard_MainService(int id, int code, void * params)
{
    KeyboardParams * pKeyboardParams = (KeyboardParams *)params;
    CKeyboard * pKeyboard = pKeyboardParams->pKeyboard;
    SDL_Event * pSDLEvent = (SDL_Event *)pKeyboardParams->pParams;
    KPD_DATA keyData;

    Keyboard_PressKey(pSDLEvent, &keyData);

    MemoryBuf_<sizeof(KPD_DATA)> buf;
    buf.Copy((Byte *)&keyData, sizeof(KPD_DATA));

    pKeyboard->GetQueue()->Write(0, buf, NULL, NULL);
}

static void _Keyboard_EnqueueEventService(int id, int code, void *params)
{
    assert(NULL != g_pKeyboard);
    MemoryBuf_<sizeof(KPD_DATA)> buf;
    buf.Copy((Byte *)params, sizeof(KPD_DATA));

    g_pKeyboard->GetQueue()->Write(0, buf, NULL, NULL);
}

CKeyboard::~CKeyboard()
{
    if (NULL != m_pEventQueue) {
        m_pEventQueue->Release();
        m_pEventQueue = NULL;
    }
    RemoveNotifier(EVENT_KEYPAD);
    RemoveNotifier(SERVICE_KEYPAD);
}

ECode CKeyboard::Initialize()
{
    AddNotifier(SERVICE_KEYPAD, (const PVoid)_Keyboard_MainService);
    AddNotifier(EVENT_KEYPAD, (const PVoid)_Keyboard_EnqueueEventService);
    return GetEventQueueSink()->CreateQueue(
                                    m_environmentId,
                                    HOST_KEYBOARD,
                                    sizeof(KPD_DATA),
                                    32,
                                    &m_pEventQueue);
}

ECode CKeyboard::Read(
    /* [in] */ Int64 offset,
    /* [in] */ Int32 numberOfBytesToRead,
    /* [out] */ MemoryBuf * pData,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return m_pEventQueue->Read(offset,
                         numberOfBytesToRead,
                         pData,
                         ppCompletionEvent);
}

ECode CKeyboard::Write(
    /* [in] */ Int64 offset,
    /* [in] */ const MemoryBuf & ebbData,
    /* [out] */ Int32 * puNumberOfBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    assert(0);
    return E_NOT_IMPLEMENTED;
}

ECode CKeyboard::Control(
    /* [in] */ Handle32 controlCode,
    /* [in] */ const MemoryBuf & ebbInData,
    /* [out] */ MemoryBuf * pOutData,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

void CKeyboard::Dispose()
{
    delete this;
}


ECode CKeyboard::S_Create(
        /* [in] */ Int32 environmentId,
        /* [out] */ IDeviceDriver ** ppKeyboard)
{
    CKeyboard * pKeyboard = NULL;
    ECode ec = NOERROR;

    pKeyboard = new CKeyboard(environmentId);
    if (NULL == pKeyboard) {
        return E_OUT_OF_MEMORY;
    }
    ec = pKeyboard->Initialize();
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    pKeyboard->AddRef();

    g_pKeyboard = pKeyboard;
    *ppKeyboard = (IDeviceDriver *)pKeyboard;
    return ec;

ErrorExit:
    if (NULL != g_pKeyboard) {
        delete g_pKeyboard;
        g_pKeyboard = NULL;
    }
    return ec;
}

CKeyboard*  CKeyboard::S_Get(
        /* [in] */ Int32 environmentId)
{
    assert(NULL != g_pKeyboard);
    return g_pKeyboard;
}

